#include "stdafx.h"
#include "TinyCapture.h"
#include "TinyCaptureDlg.h"
#include "GLHandler.h"
#include "Utility.h"
#include <process.h>
using namespace Utility;


#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CTinyCaptureDlg::CTinyCaptureDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTinyCaptureDlg::IDD, pParent), 
	mGraphic(mComPortHander),
	mGyroViewer(DEF_BASE_GYRO),
	mAccViewer(DEF_BASE_ACC),
	mMagViewer(DEF_BASE_MAG),
	mEularViewer(DEF_BASE_EULAR),
	mOnRecord(false),
	mIsRecording(false),
	mDataFileRecorder("DataRecord.txt"),
	mLogFileRecorder("Log.txt"),
	mComPortHander(mLogFileRecorder)
{	
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	mCurveViewerArry.push_back(&mGyroViewer);
	mCurveViewerArry.push_back(&mAccViewer);
	mCurveViewerArry.push_back(&mMagViewer);
	mCurveViewerArry.push_back(&mEularViewer);

	for (int i=0; i< 12; ++i)
	{
		CStatic* pClrRect = new CStatic();
		mClrRects.push_back(pClrRect);
	}
	for (int i=0; i<12; ++i)
	{
		CStatic* mDataVal = new CStatic();
		mDataTexts.push_back(mDataVal);
	}
}

CTinyCaptureDlg::~CTinyCaptureDlg()
{
	for (size_t i =0; i<mClrRects.size(); ++i)
	{
		delete mClrRects[i];
	}
	for (size_t i=0; i<mDataTexts.size(); ++i)
	{
		delete mDataTexts[i];
	}
}

void CTinyCaptureDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_GRAPHIC,	 mGraphic);
	DDX_Control(pDX, IDC_GYROCURVE,	 mGyroViewer);
	DDX_Control(pDX, IDC_ACCCURVE,   mAccViewer);
	DDX_Control(pDX, IDC_MAGCURVE,   mMagViewer);
	DDX_Control(pDX, IDC_EULARCURVE, mEularViewer);
	//all the clr rects:
	for (int i=0; i<12; ++i)
	{
		DDX_Control(pDX, WM_USER + i, *(mClrRects[i]));
	}
	for (int i=0; i<12; ++i)
	{
		DDX_Control(pDX, CURRENT_USER_ID + i, *(mDataTexts[i]));
	}
}

BEGIN_MESSAGE_MAP(CTinyCaptureDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_WM_SIZING()
	ON_WM_ERASEBKGND()
	ON_COMMAND(ID_CONNECT, &CTinyCaptureDlg::OnConnect)
	ON_COMMAND(ID_DISCONNECT, &CTinyCaptureDlg::OnDisconnect)
	ON_COMMAND(ID_CONFIG_SELCOMPORT, &CTinyCaptureDlg::OnConfigSelcomport)
	ON_COMMAND(IDC_TB_RECORD, &CTinyCaptureDlg::onRecordData)
	ON_COMMAND(IDC_TB_STOP, &CTinyCaptureDlg::onStopRecordData)
	ON_WM_TIMER()
END_MESSAGE_MAP()

//EasySize Macro
BEGIN_EASYSIZE_MAP(CTinyCaptureDlg)
	EASYSIZE(IDC_GRAPHIC,ES_BORDER,ES_BORDER,ES_BORDER,ES_BORDER,0)
	EASYSIZE(IDC_GRAPHICSTATIC,ES_BORDER,ES_BORDER,ES_BORDER,ES_BORDER,0)
END_EASYSIZE_MAP

BOOL CTinyCaptureDlg::dcInitialization()
{
	//set OpenGL's DC
	mGraphic.m_pDC=(CClientDC *)mGraphic.GetDC();
	PIXELFORMATDESCRIPTOR pfd=
	{
		sizeof(PIXELFORMATDESCRIPTOR),
		1,
		PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|
		PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		24,
		0,0,0,0,0,0,
		0,
		0,
		0,
		0,0,0,0,
		16,
		0,
		0,
		PFD_MAIN_PLANE,
		0,
		0,0,0
	};
	int pf =ChoosePixelFormat(mGraphic.m_pDC->GetSafeHdc(),&pfd);
	if (pf == 0)
	{
		return FALSE;
	}
	BOOL rt=SetPixelFormat(mGraphic.m_pDC->GetSafeHdc(),pf,&pfd);
	hglrc=wglCreateContext(mGraphic.m_pDC->GetSafeHdc());
	wglMakeCurrent(mGraphic.m_pDC->GetSafeHdc(),hglrc);
	return TRUE;
}

void CTinyCaptureDlg::initEssentialStuff()
{
	//set the view port when initialize the dialog
	CRect rect(0,0,0,0);
	mGraphic.GetClientRect(&rect);
	GLHandler::setViewPort((GLsizei)rect.right, (GLsizei)rect.bottom);

	//rendering attribute setting
	if(! GLHandler::initGL() )
	{
		Helper::errInfoDialog(L"Failed to init glew!");
		exit(0);
	}

	//for the background brush
	HBRUSH brDlgBk=(HBRUSH)::GetSysColorBrush(COLOR_3DFACE);  
	m_pBkgBrush=CBrush::FromHandle(brDlgBk);

	//solve the flicker problem
	LONG style = GetWindowLong(GetDlgItem(IDC_GRAPHICSTATIC)->GetSafeHwnd(),GWL_STYLE);
	style = style | WS_CLIPSIBLINGS ;
	SetWindowLong(GetDlgItem(IDC_GRAPHICSTATIC)->GetSafeHwnd(),GWL_STYLE,style);

	//initialize all the curve viewers 
	for (size_t i=0; i<mCurveViewerArry.size(); ++i)
	{
		mCurveViewerArry[i]->initViewer();
	}

	//set timer for curve drawing and graphic showing
	startTimer();

	//init tool bar
	initToolBar();
	//maximize window
	//this->ShowWindow(SW_MAXIMIZE);
}

void CTinyCaptureDlg::setClrRectColor(COLORREF clr, CStatic* clrRect)
{
	CClientDC dc(clrRect);
	CRect rect;
	clrRect->GetClientRect(&rect);
	dc.FillSolidRect(&rect, clr);
}

BOOL CTinyCaptureDlg::initToolBar()
{
	if(!mToolbar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | 
		WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | 
		CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || 
		!mToolbar.LoadToolBar(IDR_TOOLBAR1))
	{
		EndDialog(IDCANCEL);
		return FALSE;
	}
	RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST,0);
	moveToolBar();
	SIZE button = {30,30};
	SIZE image = {20,20};
	mToolbar.SetSizes(button, image);
	mToolbar.GetToolBarCtrl().EnableButton(IDC_TB_RECORD);
	return TRUE;
}

void CTinyCaptureDlg::moveToolBar()
{
	CRect rect;
	GetClientRect(&rect);
	mToolbar.MoveWindow( 0, 0, rect.right, 32, 1 );
}

BOOL CTinyCaptureDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	SetIcon(m_hIcon, TRUE);			
	SetIcon(m_hIcon, FALSE);		

	//init EASYSIZE macro 
	INIT_EASYSIZE;
	//int DC for OpenGL
	if (dcInitialization())
	{
		initEssentialStuff();
	}
	else
	{
		Helper::errInfoDialog(L"Create OpenGL environment failed");
		::exit(1);
	}
	return TRUE;   
}

void CTinyCaptureDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

void CTinyCaptureDlg::drawClrRects()
{
	//set the clr rects
	for (int i=0; i<12; ++i)
	{
		int mod = i%3;
		switch (mod)
		{
		case 0:
			setClrRectColor(RGB(255, 0, 0), mClrRects[i]);
			break;
		case 1:
			setClrRectColor(RGB(0, 255, 0), mClrRects[i]);
			break;
		case 2:
			setClrRectColor(RGB(0, 0, 255), mClrRects[i]);
		default:
			break;
		}
	}
}

void CTinyCaptureDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{	
		CDialog::OnPaint();
	}
	drawClrRects();
}

HCURSOR CTinyCaptureDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

int CTinyCaptureDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;
	return 0;
}

void CTinyCaptureDlg::OnDestroy()
{
	wglMakeCurrent(NULL,NULL);
	wglDeleteContext(hglrc);
	m_pBkgBrush->DeleteObject();
	CDialog::OnDestroy();
}

void CTinyCaptureDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);
	UPDATE_EASYSIZE;
	if (::IsWindow(mToolbar.m_hWnd))
	{
		moveToolBar();
	}
}

void CTinyCaptureDlg::OnSizing(UINT fwSide, LPRECT pRect)
{
	CDialog::OnSizing(fwSide, pRect);
//  EASYSIZE_MINSIZE(400,400,fwSide,pRect);
}

BOOL CALLBACK CTinyCaptureDlg::EnumChildProc(HWND hwnd, LPARAM lParam)
{
	CWnd *pWnd=CWnd::FromHandle(hwnd);
	if (pWnd)
	{
		pWnd->Invalidate(FALSE);
		return TRUE;
	}
	return FALSE;
}

BOOL CTinyCaptureDlg::OnEraseBkgnd(CDC* pDC) 
{
	//calculate the necessary area where needs redraw
// 	EnumChildWindows(this->m_hWnd, EnumChildProc, NULL);
	CRgn rgnDlg, rgnGraphic;
	CRect rectClient,rectGLArea,rectGyro;
	this->GetClientRect(&rectClient);
	mGraphic.GetWindowRect(&rectGLArea);
	ScreenToClient(&rectGLArea);
	rgnDlg.CreateRectRgnIndirect(rectClient);
	rgnGraphic.CreateRectRgnIndirect(rectGLArea);
	CRgn rg3;
	rg3.CreateRectRgn(0,0,0,0);
	if (rg3.CombineRgn(&rgnDlg,&rgnGraphic,RGN_XOR)!=ERROR)
	{
		pDC->FillRgn(&rg3,m_pBkgBrush);
	}
	rgnDlg.DeleteObject();
	rgnGraphic.DeleteObject();
	rg3.DeleteObject();

	return TRUE;
}

void CTinyCaptureDlg::startTimer()
{
	mUIViewTimer = this->SetTimer(1, 20, NULL);
	mOpenGLTimer = mGraphic.SetTimer(1, 20, NULL);
}

void CTinyCaptureDlg::endTimer()
{
	this->KillTimer(mUIViewTimer);
// 	mGraphic.KillTimer(mOpenGLTimer);
}

void CTinyCaptureDlg::startRecordLog()
{
	mLogFileRecorder.openFile();
	mLogFileRecorder.writeFileHeader();
}

void CTinyCaptureDlg::OnConnect()
{ 
	if (mComPortHander.isComPortOpen())
	{
		Helper::errInfoDialog(L"ComPort Opened, disconnect first.");
		return;
	}
	if (mComPortHander.openComPort())
	{
		mComPortHander.setWriteCommand(0x80);
		if(mComPortHander.writeCommandToComPort())
		{
			startRecordLog();
			mComPortHander.startReadFromComPort();
			mUIViewTimer = this->SetTimer(1, 20, NULL);
		}
		else
			Helper::errInfoDialog(L"write command failed");
	}
	else
	{
		Helper::errInfoDialog(L"Open ComPort failed\n\nPlease check configuration");
	}
}

void CTinyCaptureDlg::OnDisconnect()
{ 
	mComPortHander.endReadFromComPort();
	mComPortHander.closeComPortHanle();
	mLogFileRecorder.writeStringToFile("Disconnected.");
	mLogFileRecorder.flushAndNewLine();
	mIsRecording = false;
	//end curve timer
	endTimer();
}

BOOL CTinyCaptureDlg::PreTranslateMessage(MSG* pMsg)
{
	//dispatch mouse message to graphic area
	if (WM_MOUSEWHEEL==pMsg->message)
	{
		::SendMessage(mGraphic.m_hWnd,pMsg->message,pMsg->wParam,pMsg->lParam);
		return TRUE;
	}
	return CDialog::PreTranslateMessage(pMsg);
}

void CTinyCaptureDlg::OnConfigSelcomport()
{
	mComPortConfiger.DoModal();
	mComPortHander.setDeviceID(mComPortConfiger.getSelDeviceID());
	mComPortHander.setComPortID(mComPortConfiger.getSelComPortID());
}

void CTinyCaptureDlg::updateCurveViewer(float* dataVal, CurveViewer& curViewer)
{
	for (int i=0; i<3; ++i)
	{
		curViewer.drawCurve(dataVal[i], i);
	}
	curViewer.forwardXPos();
	curViewer.Invalidate(FALSE);
}

void CTinyCaptureDlg::updateDataValues()
{
	float* gyroVal = mComPortHander.getGyro();
	CString dataStr;
	for (int i=0; i<3; ++i)
	{
		dataStr = Helper::convertToCString(gyroVal[0]);
		mDataTexts[i]->SetWindowText(dataStr);
	}
	float* accVal = mComPortHander.getAcc();
	for (int i=3; i<6; ++i)
	{		
		dataStr = Helper::convertToCString(accVal[i-3]);
		mDataTexts[i]->SetWindowText(dataStr);
	}
	float* magVal = mComPortHander.getMag();
	for (int i=6; i<9; ++i)
	{
		dataStr = Helper::convertToCString(magVal[i-6]);
		mDataTexts[i]->SetWindowText(dataStr);
	}
	dataStr = Helper::convertToCString(mComPortHander.getRoll());
	mDataTexts[9]->SetWindowTextW(dataStr);
	dataStr = Helper::convertToCString(mComPortHander.getPitch());
	mDataTexts[10]->SetWindowTextW(dataStr);
	dataStr = Helper::convertToCString(mComPortHander.getYaw());
	mDataTexts[11]->SetWindowTextW(dataStr);
}

void CTinyCaptureDlg::OnTimer(UINT_PTR nIDEvent)
{
	if (mComPortHander.isReadingComPort())
	{
		//update curve viewers
		float* gyroVal = mComPortHander.getGyro();
		updateCurveViewer(gyroVal, mGyroViewer);
		float* accVal = mComPortHander.getAcc();
		updateCurveViewer(accVal, mAccViewer);
		float* magVal = mComPortHander.getMag();
		updateCurveViewer(magVal, mMagViewer);
		float	eularVal[3];
		eularVal[0] = mComPortHander.getRoll();
		eularVal[1]	= mComPortHander.getPitch();
		eularVal[2] = mComPortHander.getYaw();
		updateCurveViewer(eularVal, mEularViewer);

		//update data values
		updateDataValues();

		//record data to file
		if (mIsRecording)
		{
			recordDataToFile();
		}
	}
	CDialog::OnTimer(nIDEvent);
}

void CTinyCaptureDlg::startRecordData()
{
	mDataFileRecorder.openFile();
	mDataFileRecorder.writeFileHeader();
	mIsRecording = true;
}

void CTinyCaptureDlg::recordDataToFile()
{
	float* gyroVal = mComPortHander.getGyro();
	CString dataStr;
	for (int i=0; i<3; ++i)
	{
		dataStr = Helper::convertToCString(gyroVal[0]);
		mDataFileRecorder.writeStringToFile(Helper::convertCStringToString(dataStr), 10);
	}
	float* accVal = mComPortHander.getAcc();
	for (int i=3; i<6; ++i)
	{		
		dataStr = Helper::convertToCString(accVal[i-3]);
		mDataFileRecorder.writeStringToFile(Helper::convertCStringToString(dataStr), 10);
	}
	float* magVal = mComPortHander.getMag();
	for (int i=6; i<9; ++i)
	{
		dataStr = Helper::convertToCString(magVal[i-6]);
		mDataFileRecorder.writeStringToFile(Helper::convertCStringToString(dataStr), 10);
	}
	dataStr = Helper::convertToCString(mComPortHander.getRoll());
	mDataFileRecorder.writeStringToFile(Helper::convertCStringToString(dataStr), 10);
	dataStr = Helper::convertToCString(mComPortHander.getPitch());
	mDataFileRecorder.writeStringToFile(Helper::convertCStringToString(dataStr), 10);
	dataStr = Helper::convertToCString(mComPortHander.getYaw());
	mDataFileRecorder.writeStringToFile(Helper::convertCStringToString(dataStr), 10);
	mDataFileRecorder.flushAndNewLine();
}

void CTinyCaptureDlg::onRecordData()
{
	mOnRecord = true;
	if (mOnRecord && mComPortHander.isReadingComPort())
	{
		mToolbar.GetToolBarCtrl().EnableButton(IDC_TB_RECORD, FALSE);
		startRecordData();
	}
	else
		Helper::errInfoDialog(L"Record only when reading data from com port.", L"Note");
}

void CTinyCaptureDlg::onStopRecordData()
{
	mOnRecord = false;
	mIsRecording = false;
	mToolbar.GetToolBarCtrl().EnableButton(IDC_TB_RECORD, TRUE);
}

